﻿using ControlzEx.Standard;

using ExcelSystem.Model;
using ImTools;
using MathNet.Numerics;
using Microsoft.VisualBasic.ApplicationServices;
using Newtonsoft.Json;
using NPOI.SS.Formula;
using NPOI.SS.Formula.Eval;
using NPOI.SS.Formula.Functions;
using NPOI.SS.UserModel;
using NPOI.Util.ArrayExtensions;
using NPOI.Util.Collections;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace ExcelSystem.ToolHelper
{
    /// <summary>
    /// BOM参数
    /// </summary>
    public class BOMPar
    {

        /// <summary>
        /// 所有可能使用的属性集合
        /// </summary>
        private List<BaseProperty> propertiesOrigin { get; set; }
        /// <summary>
        /// 数据库基础属性
        /// </summary>
        private List<BaseProperty> properties { get; set; }

        private List<Model.Formula> formulaList { get; set; }


        ExcelContext ExcelContext = ExcelContentFactory.GetInstance();

        public BOMPar(Order order, Material material, BOM bom, List<Model.Formula> formulaList = null)
        {
            this.formulaList = formulaList;
            propertiesOrigin = new List<BaseProperty>();
            GetPropertyOrigin(order, material, bom);
            //获取所有基础参数
            var pars = ExcelContext.Formulas.Where(t => t.IsBase == true).ToList();
            //为基础参数赋值
            properties=new List<BaseProperty>();
            foreach (var par in pars)
            {
                switch(par.FormulaType)
                {
                    case 0:
                        //仅需要数字
                        properties.Add(new BaseProperty() { Name=par.ReflectionProperty,Value= GetPropertyValue(par.Property).ExtractNumberString(),Property=par.Property });
                        break;
                    case 1:
                        //全文
                        properties.Add(new BaseProperty() { Name = par.ReflectionProperty, Value = GetPropertyValue(par.Property), Type=1, Property = par.Property });
                        break;
                    case 2:
                        //尺寸
                        properties.Add(new BaseProperty() { Name = par.ReflectionProperty, Value = GetPropertyValue(par.Property), Type = 2, Property = par.Property });
                        break;
                    case 3:
                        //字符串
                        properties.Add(new BaseProperty() { Name = par.ReflectionProperty, Value = GetPropertyValue(par.Property), Type = 3, Property = par.Property });
                        break;
                    case 5:
                        //枚举
                        List<string> strings = new List<string>();
                        strings = JsonConvert.DeserializeObject<List<string>>(par.Value);
                        properties.Add(new BaseProperty() { Name = par.ReflectionProperty, Value = GetPropertyValue(par.Property), Type = 5, Property = par.Property });
                        break;
                }
            }
       
        }

        /// <summary>
        /// 获取属性值的集合
        /// </summary>
        /// <param name="order"></param>
        /// <param name="material"></param>
        /// <param name="bom"></param>
        public void GetPropertyOrigin(Order order, Material material,BOM bom)
        {
            typeof(Order).GetProperties().ForEach(t =>
            propertiesOrigin.Add(new BaseProperty() { Name = t.Name, Value = t.GetValue(order)==null?null: t.GetValue(order).ToString() })
            );
            typeof(Material).GetProperties().ForEach(t =>
           propertiesOrigin.Add(new BaseProperty() { Name = t.Name, Value = t.GetValue(material) == null ? null : t.GetValue(material).ToString() })
           );
            typeof(BOM).GetProperties().ForEach(t =>
            propertiesOrigin.Add(new BaseProperty() { Name = t.Name, Value = t.GetValue(bom) == null ? null : t.GetValue(bom).ToString() })
            );
        }

        public string GetPropertyValue(string name, int type=0)
        {
            var pro = propertiesOrigin.FirstOrDefault(t => t.Name == name);
            if(type==5)
            {
                var child = ExcelContext.Formulas.FirstOrDefault(t => t.Name == pro.Value);
                if(child!=null)
                pro.Value = child.Value;

            }
            if(pro!=null)
            {
                return pro.Value;
            }
            else
            {
                return null;
            }
        }


        /// <summary>
        /// 解析公式
        /// </summary>
        /// <param name="par"></param>
        /// <returns></returns>
        public  string FindFormulas( BOM_Info par)
        {
            string result = "";
            //获取公式
            var formulas = ExcelContext.Formulas.FirstOrDefault(t => t.Name.TrimEnd() == par.Key);
            string cal = "";
            //有自带公式则用自带公式
            if (!string.IsNullOrEmpty(par.Cal))
            {
                cal = par.Cal;
            }
            else if (formulas != null)
            {
                cal= formulas.Value;
            }
            else
            {
                MessageBox.Show($"缺少公式{par.Key}");
                return "";
            }

            cal = cal.Replace("\r", "").Replace("\n", "");
            //拆解自定义公式
            if(cal.Contains("主机"))
            {
                string name = "";
                var host = propertiesOrigin.FirstOrDefault(t => t.Name == "HostSeries");
                if (host!=null)
                {
                    if(host.Value == "XOGM1.9")
                    {
                        name = "339";
                    }
                    else
                    {
                        name = "329";
                    }
                }
                else
                {
                    name = "错误";
                }
                cal = cal.Replace("主机", name);
            }
            //包含EXCEL公式 DZ+({if《U28<250》?错误:U28})/2-(D1)/2
            if (cal.Contains("if") && cal.Contains("《"))
            {


                string[] strings = ["<", "<=", "=", ">", ">="];
                int begin = cal.IndexOf("{");
                int end = cal.IndexOf("}");
                //获取字符串
                string data = cal.Substring(begin, end - begin + 1);
                //对比部分
                string par0 = data.Substring(data.IndexOf("《") + 1, data.IndexOf("》") - data.IndexOf("《") - 1);
                var list = par0.Split(strings, StringSplitOptions.None);
                var op = par0.Split(list, StringSplitOptions.RemoveEmptyEntries);
                //结果部分
                string par2 = data.Substring(data.IndexOf("?") + 1, data.IndexOf("}") - data.IndexOf("?") - 1);
                var answer = par2.Split(':');
                //得到对比结果
                string an = IfAnswer(list.ToList(), op[0], answer.ToList());
                //替换对比内容
                cal = cal.Replace(data, $"({an})") ;


            }
            //原始对比语句
            if (cal.Contains("IF") && cal.Contains("AND"))
            {


                string[] strings = ["<", "<=", "=", ">", ">="];
                cal = cal.Replace("\"", "");
                var begin = cal.GetStrIndex("(");
                var end = cal.GetStrIndex(")");
                string data = cal.Substring(begin[0], end[end.Count-1]- begin[0]+1);
                //对比部分
                string par0 = cal.Substring(begin[begin.Count-1]+1, end[0] - begin[begin.Count - 1]-1);
                var list = par0.Split(strings, StringSplitOptions.None);
                var op = par0.Split(list, StringSplitOptions.RemoveEmptyEntries);
                //结果部分
                string par2 = cal.Substring(end[0] + 2, end[end.Count-1] - end[0] - 3);
                var answer = par2.Split(',');
                //得到对比结果
                string an = IfAnswer(list.ToList(), op[0], answer.ToList());
                //替换对比内容
                cal = cal.Replace(data, $"({an})");

               


            }
            //字符串提取  专指辅料的长    DZ+(240+100)/2+ML+(D1)/2-160+160-MID(AM1050,1,3)/2 
            if (cal.Contains("MID") && cal.Contains("AM"))
            {
                int begin = cal.IndexOf("MID(");
                int end = cal.IndexOf(")", begin);
                //获取字符串
                string data = cal.Substring(begin, end - begin + 1);
                var size = propertiesOrigin.FirstOrDefault(t => t.Name == "AccessoriesSize");
                if (size != null)
                {
                
                    cal = cal.Replace(data, $"({size.Value.Split('*')[0]})");

                }



            }

            if (cal.Contains("CarOuterWidth"))
            {
          
                var size = propertiesOrigin.FirstOrDefault(t => t.Name == "CarOuterWidth");
                if (size != null)
                {

                    cal = cal.Replace("CarOuterWidth", $"({size.Value})");

                }



            }
            

            // 判断是否有字符串分割
            if (!cal.Contains("|"))
            {
                result = UserFormulas(cal);
            }
            else
            {
                var list = cal.Split('|');
                foreach (var item in list)
                {
                    if (item.Contains("str:"))
                    {
                        result += item.Replace("str:", "");
                    }
                    else if (!string.IsNullOrEmpty(item))
                    {
                        result += UserFormulas(item);
                    }
                }


            }
            //result = UserFormulas(formulas.Value);


            return result;
        }

        public  string Set2Value( string par)
        {
            if (par.Contains("V8"))
            {
                var data = propertiesOrigin.FirstOrDefault(t => t.Name == "CarOuterWidth");
                par= par.Replace("V8", data.Value);
            }
            return par;
        }


        /// <summary>
        /// 解析IF公式
        /// </summary>
        /// <param name="input"></param>
        /// <param name="formula"></param>
        /// <param name="answer"></param>
        /// <returns></returns>
        public string IfAnswer(List<string> input, string formula, List<string> answer)
        {
            for (int i = 0; i < input.Count; i++)
            {
                input[i] = GetValueByU_number(input[i]);
            }
           
            bool bo = false;
            switch (formula)
            {
                case "<":
                    bo = Convert.ToDecimal(Cal(Cal(input[0])) ) < Convert.ToDecimal(Cal(input[1]));
                    break;
                case "<=":
                    bo = Convert.ToDecimal(Cal(input[0])) <= Convert.ToDecimal(Cal(input[1]));
                    break;
                case "==":
                    bo = Convert.ToDecimal(Cal(input[0])) == Convert.ToDecimal(Cal(input[1]));
                    break;
                case "=":
                    bo = Convert.ToDecimal(Cal(input[0])) == Convert.ToDecimal(Cal(input[1]));
                    break;
                case ">":
                    bo = Convert.ToDecimal(Cal(input[0])) > Convert.ToDecimal(Cal(input[1]));
                    break;
                case ">=":
                    bo = Convert.ToDecimal(Cal(input[0])) >= Convert.ToDecimal(Cal(input[1]));
                    break;
                case "!=":
                    bo = Convert.ToDecimal(Cal(input[0])) != Convert.ToDecimal(Cal(input[1]));
                    break;
            }

            for (int i = 0; i < answer.Count; i++)
            {
                answer[i] = GetValueByU_number(answer[i]);
            }
            

            return bo ? answer[0] : answer[1];
        }


        public string GetValueByU_number(string number)
        {
            //number 可能是 K U15 WT
     
            var Formula = ExcelContext.Formulas.FirstOrDefault(t => t.ReflectionProperty == number);
            //K WT
            if (Formula != null)
            {
                if(!string.IsNullOrEmpty(Formula.Property))
                {
                    number = Formula.Property;
                }
                else if(!string.IsNullOrEmpty(Formula.ExcelName))
                {
                    if(!string.IsNullOrEmpty(Formula.Property))
                    {
                        number = Formula.Property;
                    }
                    else
                    {
                        foreach (var item in ExcelContext.Formulas)
                        {
                            if(!string.IsNullOrEmpty(Formula.ExcelValue)&& !string.IsNullOrEmpty(item.ExcelName) &&  Formula.ExcelValue.Contains(item.ExcelName))
                            {
                                number = Formula.Value.Replace(item.ExcelName, item.Property);
                            }
                          
                        }
                    }
                 
                }

             
            }
            else if(number.Contains("V"))
            {
                number = Row3tRow2(number);
                var V_Formula = ExcelContext.Formulas.FirstOrDefault(t => t.ReflectionProperty == number);
                if(V_Formula!=null)
                {
                    var V_value = properties.FirstOrDefault(t => t.Property == V_Formula.Property);
                    if (V_value!=null)
                    {
                        number = V_value.Value;
                    }
             
                }

            }
            //U
            else
            {
                Formula = ExcelContext.Formulas.FirstOrDefault(t => t.ExcelName == number);
                if(Formula==null)
                {
                    return number;
                }
                if (!string.IsNullOrEmpty(Formula.Property))
                {
                    number = Formula.Property;
                }
                else
                {
                    foreach (var item in ExcelContext.Formulas)
                    {
                        if (!string.IsNullOrEmpty(Formula.ExcelValue) && !string.IsNullOrEmpty(item.ExcelName) && Formula.ExcelValue.Contains(item.ExcelName))
                        {
                            number = Formula.Value.Replace(item.ExcelName, item.Property);
                        }

                    }
                }
            }

            properties.ForEach(j =>
            {
                if (number.Contains(j.Name))
                {
                    number = number.Replace(j.Name, j.Value);
                }
            });





            //ExcelContext.Formulas.ToList().ForEach(t =>
            //{
            //    if(t.ReflectionProperty== number)
            //    {
            //        var par = properties.FirstOrDefault(j => j.Name == t.ReflectionProperty);
            //        number = par.Value;
            //    }

            //    //根据U15获取属性
            //    else if (t.ExcelName != null && number == t.ExcelName)
            //    {

            //        if (string.IsNullOrEmpty(t.ExcelValue))
            //        {
            //            var par = properties.FirstOrDefault(j => j.Name == t.ReflectionProperty);
            //            number = par.Value;
            //        }
            //        else
            //        {
            //            number = t.ExcelValue;
            //            ExcelContext.Formulas.ToList().ForEach(j =>
            //            {
            //                if (!string.IsNullOrEmpty(j.ExcelName) && t.ExcelValue.Contains(j.ExcelName))
            //                {
            //                    number = number.Replace(j.ExcelName, j.Value);
            //                }
            //            });
            //            properties.ForEach(j =>
            //            {
            //                if (number.Contains(j.Name))
            //                {
            //                    number = number.Replace(j.Name, j.Value);
            //                }
            //            });
            //        }


            //    }

            //});

            return number;  

        }


        public string UserFormulas(string calStr)
        {
         
         
            //分解公式
            char[] arr = ['+', '-', '*', '/', '(', ')'];
            //值
            var names = calStr.Split(arr);
            //运算符
            var op = calStr.Where(t => arr.Contains(t)).ToList();
            //重新组合公式
            string result = "";
            foreach (var name in names.Select((source, index) => new { source, index }))
            {

                if (op.Count > name.index)
                {
                    //乘除的运算优先级高
                    if (op[name.index] == '*' || op[name.index] == '/')
                    {
                        if(!string.IsNullOrEmpty(name.source))
                        {
                            result += $"({ReturnFormulasChild(name.source)})" + op[name.index];
                        }
                        else
                        {
                            result += op[name.index];
                        }
                        
                    }
                    else
                    {
                        result += ReturnFormulasChild(name.source) + op[name.index];
                    }


                }
                else
                {
                    result += ReturnFormulasChild(name.source);

                }
            }
            return Cal(result);
        }

        /// <summary>
        /// 分解单独参数
        /// </summary>
        /// <param name="formula"></param>
        /// <returns></returns>
        public string ReturnFormulasChild( string formula)
        {
            string result="";
            //3行 转2行  
            //3行固定值与2行固定值区别
            formula = Row3tRow2(formula);


           var f = ExcelContext.Formulas.FirstOrDefault(t => t.ReflectionProperty == formula);
            //不存在公式分解
            if(f==null)
            {
                double tem = 0;
                bool isNumber= double.TryParse(formula, out tem);
                //数字 
                if(isNumber)
                {
                    return tem<0?$"({formula})": formula;
                }
                else if (formula.Contains("&"))//尺寸
                {
                    
                    properties.ForEach(p =>
                    {
                        //获取尺寸映照
                        if (p.Type==2&&formula.Contains(p.Name))
                        {
                            //获取 要获取尺寸的的位置
                            int index = Convert.ToInt32(formula.Split(p.Name)[1]);
                            //获取尺寸 全称 200*100*50
                            var size = propertiesOrigin.FirstOrDefault(t => t.Name == p.Property);
                            //获取对应单独尺寸
                            result = size.Value.Split("*")[index].ToString();
                        }

                    });
                    return result;
                }
                else if(formula.Contains("|"))//字符串
                {
                    //单独提取其中的字符串
                    string str = formula.Substring(1, formula.LastIndexOf("|") - 1);
                }
                //本事就是属性值
                else
                {
                    properties.ForEach(p =>
                    {
                        if(p.Property == formula)
                        {
                            result = p.Value;
                           
                        }
                    });
                    return result;
                }
             


            }
            else//存在公式分解
            {
              
                ////不相等表示公式可继续分解
                if (f.Value != f.ReflectionProperty)
                {
                    //特殊处理：枚举  获取Origin真实Name 并再次查询表  例如表格显示： 后置1区  然后拿这个值去数据库差 

                    if (f.FormulaType == 5)
                    {
                       
                        //获取当前名称
                        var name_db = propertiesOrigin.FirstOrDefault(t => t.Name == f.Property);
                        //根据当前名称查询值
                        var child = ExcelContext.Formulas.FirstOrDefault(t => t.Name == (name_db == null ? "" : name_db.Value));
                        if (child != null)
                            result = child.Value;

                    }


                    //分解公式
                    char[] arr = ['+', '-', '*', '/'];
                    //值
                    var names = f.Value.Split(arr);
                    //运算符
                    var op = f.Value.Where(t => arr.Contains(t)).ToList();
                    foreach (var name in names.Select((source, index) => new { source, index }))
                    {

                        if (op.Count > name.index)
                        {
                            //乘除的运算优先级高
                            if ((op[name.index] == '*' || op[name.index] == '/') || (op[name.index] == '*' || op[name.index] == '/'))
                            {
                                result += $"({ReturnFormulasChild(name.source)})" + op[name.index];
                            }
                            else
                            {
                                result += ReturnFormulasChild(name.source) + op[name.index];
                            }


                        }
                        else
                        {
                            result += ReturnFormulasChild(name.source);

                        }
                    }
                }
                else
                {
                    result = f.Value;
                }
            }

            return result;
        }


        public string Row3tRow2(string formula)
        {
            //3行 转2行  
            //3行固定值与2行固定值区别
            formula = formula.Replace("V32", "V14-V19");
            formula = formula.Replace("V33", "V15-V20");

            if (formulaList != null && formula.Contains("V"))
            {
                formulaList.Where(t => t.ExcelName != null && t.ExcelName.Contains("U")).ToList().ForEach(t =>
                {
                    //针对3行进行转换  (U)V10+2=U12 
                    //普通基础参数替换
                    var eName = "V" + (Convert.ToInt32(t.ExcelName.Replace("U", "")) - 2);
                    if (eName != "V13" && formula.Contains(eName))
                    {
                        formula = formula.Replace(eName, t.Value);
                        return;
                    }


                });
            }
            return formula;
        }
        /// <summary>
        /// 将参数的内容计算
        /// </summary>
        public string Cal(string calStr)
        {
            string result = "";

         


            properties.ForEach(prop =>
            {
                if (calStr.Contains(prop.Name))
                {
                    var value = prop.Value;
                    if (!string.IsNullOrEmpty(value))
                    {
                        if (calStr == prop.Name)
                            calStr = value.ToString();
                        else
                            calStr = calStr.ReplaceNumber(prop.Name, Convert.ToDecimal(value) < 0 ? $"0{value}" : value.ToString());
                    }
                   


                }

            });
            CalcOperation calcOperation = new CalcOperation();
            try
            {
                Convert.ToDecimal(calStr);
                return calStr;
            }
            catch (Exception ex)
            {
                try
                {
                    result = calcOperation.CalcStr(calStr).ToString();
                    return result;
                }catch(Exception e) {
                    return "错误";
                }
              

            }


        }
    }

    public class BOM_Info
    {
        public string Key { get; set; }
        public string Value { get; set; }

        public string Cal { get; set; }

       
    }

    public class BaseProperty
    {
        public string Name { get; set; }

        public string Property { get; set; }
        public string Value { get; set; }

        public int Type { get; set; }
    }


}
